﻿#pragma once

#include "argument/box_argument.hh"
#include "box/memory_allocator.hh"
#include "box/proc_stat.hh"
#include "box/service_logger.hh"
#include "command/command.hh"
#include "component/component.hh"
#include "config/box_config.hh"
#include "csv/csv_reader.hh"
#include "klogger/interface/logger.h"
#include "root/rpc_proxy.h"
#include "root/rpc_statistics.hh"
#include "root/rpc_stub.h"
#include "time/local_system_time.hh"
#include <cstdint>
#include <ctime>
#include <functional>
#include <memory>

namespace rpc {
class Proxy;
class Transport;
template <typename T, typename TransT>
std::shared_ptr<T> getService(TransT transport, bool attached, rpc::Rpc *);
template <typename T, typename TransT>
std::shared_ptr<T> getService(GlobalIndex globalIndex, TransT transport,
                              bool attached, rpc::Rpc *);
} // namespace rpc

namespace kratos {
namespace http {
class HttpBase;
}
} // namespace kratos

namespace kratos {
namespace redis {
class Redis;
}
} // namespace kratos

namespace kratos {
namespace time {
class LocalTime;
}
} // namespace kratos

namespace kratos {
namespace console {
class BoxConsole;
}
} // namespace kratos

namespace kratos {
namespace lua {
class LuaService;
}
} // namespace kratos

namespace kratos {
namespace component {
class Component;
}
} // namespace kratos

namespace kratos {
namespace service {

/**
 *template class to test whether class has uuid method
 */
template <typename T> struct has_uuid_method {
private:
  typedef std::true_type yes;
  typedef std::false_type no;

  template <typename U>
  static auto test(int) -> decltype(std::declval<U>().uuid() == 1, yes());
  template <typename> static no test(...);

public:
  static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value;
};

/**
 * 自动销毁回调函数
 */
class CallbackAutoDeleter {
public:
  virtual ~CallbackAutoDeleter() {}
  virtual auto get_cb_id() -> std::uint32_t = 0;
};

class Scheduler;
class CoroRunner;
class ServiceLogger;
class Command;
class Util;
class CoManager;

using SchedulePtr = std::unique_ptr<kratos::service::Scheduler>;
using LoggerPtr = std::unique_ptr<kratos::service::ServiceLogger>;
using LocalTimePtr = std::unique_ptr<kratos::time::LocalTime>;
using HttpPtr = std::unique_ptr<kratos::http::HttpBase>;
using RedisPtr = std::unique_ptr<kratos::redis::Redis>;
using CommandPtr = std::unique_ptr<kratos::service::Command>;
using CsvManagerPtr = std::unique_ptr<kratos::util::CsvManager>;
using BoxConsolePtr = std::unique_ptr<kratos::console::BoxConsole>;
using LuaServicePtr = std::unique_ptr<kratos::lua::LuaService>;
using UtilPtr = std::unique_ptr<kratos::service::Util>;
using CallbackAutoDeleterPtr =
    std::unique_ptr<kratos::service::CallbackAutoDeleter>;
enum class TransEvent {
  CONNECT = 1,
  CLOSE,
};
using TransportCallback =
    std::function<void(TransEvent, std::uint32_t, rpc::TransportPtr)>;
template <typename T>
using ProxyCallback = std::function<void(std::shared_ptr<T>, bool)>;
using CoFunction = std::function<void(void)>;
using CoManagerPtr = std::unique_ptr<CoManager>;

/**
 * @brief 用户使用的上下文接口，用来调用ServiceBox提供的功能
 * @detail
 * 内部封装了ServiceBox的实现细节，对外提供统一的接口，这个也是用户服务内调用ServiceBox
 * 的唯一接口，在用户组件内通过getContext得到ServiceContext接口指针，服务容器
 * 保证ServiceContext在组件被卸载前都是有效的，通过这个接口服务容器提供了基础的跨平台功能，包含：
 * 1. 服务注册
 * 2. 服务发现
 * 3. 日志
 * 4. 获取容器启动参数
 * 5. 获取容器启动配置
 * 6. 获取容器配置器
 * 7. 定时器
 * 8. 服务获取
 * 9. HTTP客户端/服务器
 * 10. 内存分配器
 * 11. 外部命令处理
 * 12. Redis客户端
 * 13. 服务容器统计器
 * 14. 模块日志
 * 15. 本地时间计算
 * 16. CSV管理
 * 17. 控制台
 * 18. Lua服务
 * 19. Util工具
 */
class ServiceContext {
public:
  virtual ~ServiceContext() {}
  /**
   * \brief 注册服务.
   * 向集群内注册一个服务，注册成功后集群内任何服务容器内的服务都可以看到这个服务并
   * 可以使用这个服务，服务名是一个目录结构类似:/a/b/c/d...,页节点为实际服务
   * @param name 服务名
   * @retval true 成功
   * @retval false 失败
   */
  virtual auto register_service(const std::string &name) -> bool = 0;
  /**
   * 取消服务注册.
   * @param name 服务名
   * @retval true 成功
   * @retval false 失败
   */
  virtual auto unregister_service(const std::string &name) -> bool = 0;
  /**
   * 取得启动命令行参数
   *
   * \return BoxArgument引用
   */
  virtual auto get_argument() const -> const argument::BoxArgument & = 0;
  /**
   * 写日志, [线程安全].
   * @param log_level 日志等级 @see klogger::Logger
   * @param log_line 日志行
   */
  virtual auto write_log_line(int log_level, const std::string &log_line)
      -> void = 0;
  /**
   * 取得配置器.
   *
   * @return BoxConfig 引用
   */
  virtual auto get_config() const -> kratos::config::BoxConfig & = 0;
  /**
   * 关闭系统
   */
  virtual auto shutdown() -> void = 0;
  /**
   * 协程睡眠
   * @param ms 毫秒s
   */
  virtual auto sleep_co(std::time_t ms) -> void = 0;
  /**
   * 异步获取服务代理, 帮助函数
   *
   * auto_deleter_ptr需要保证生命周期，建议作为类的成员变量
   *
   * @param [IN OUT] auto_deleter_ptr 回调自动化销毁智能指针引用
   * @param cb TransportCallback
   */
  template <typename T>
  auto get_proxy_helper(CallbackAutoDeleterPtr &auto_deleter_ptr,
                        TransportCallback cb) -> void {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto_deleter_ptr = get_proxy<T>(cb);
  }
  /**
   * 异步获取服务代理, 帮助函数
   *
   * auto_deleter_ptr需要保证生命周期，建议作为类的成员变量
   *
   * @param service_name 服务名
   * @param [IN OUT] auto_deleter_ptr 回调自动化销毁智能指针引用
   * @param cb TransportCallback
   */
  template <typename T>
  auto get_named_proxy_helper(const std::string &service_name,
                              CallbackAutoDeleterPtr &auto_deleter_ptr,
                              TransportCallback cb) -> void {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto_deleter_ptr = get_proxy<T>(service_name, cb);
  }
  /**
   * 异步获取服务代理
   * @param cb TransportCallback
   * @return CallbackAutoDeleterPtr, 外部持有，析构则callback销毁
   */
  template <typename T>
  auto get_proxy(TransportCallback cb) -> CallbackAutoDeleterPtr {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    return get_transport(std::to_string(T::uuid()), cb);
  }
  /**
   * 异步获取服务代理
   * @param service_name 服务名
   * @param cb TransportCallback
   * @return CallbackAutoDeleterPtr, 外部持有，析构则callback销毁
   */
  template <typename T>
  auto get_proxy(const std::string &service_name, TransportCallback cb)
      -> CallbackAutoDeleterPtr {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    return get_transport(service_name, cb);
  }
  /**
   * 异步获取服务代理
   * @param service_name 服务名
   * @param cb ProxyCallback<T>
   * @return CallbackAutoDeleterPtr, 外部持有，析构则callback销毁
   */
  template <typename T>
  auto get_proxy(const std::string &service_name, ProxyCallback<T> cb)
      -> CallbackAutoDeleterPtr {
    return get_transport(
        service_name,
        [this, cb](kratos::service::TransEvent evt, std::uint32_t cb_id,
                   std::shared_ptr<rpc::Transport> trans_ptr) -> void {
          if (cb) {
            auto prx = rpc::getService<T>(trans_ptr, true, get_rpc());
            cb(prx, true);
          }
        });
  }
  /**
   * 尝试获取服务代理,如果没有找到则立刻返回.
   * @param service_name 服务名
   * @return 代理std::shared_ptr<T>
   */
  template <typename T>
  auto try_get_proxy(const std::string &service_name) -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = try_get_transport(service_name);
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(service_name);
    }
    return prx;
  }
  /**
   * 获取服务代理,等待timeout毫秒，在等待期间会阻塞调用线程.
   * @param service_name 服务名
   * @param timeout 最长等待时间, 毫秒
   * @return 代理std::shared_ptr<T>
   */
  template <typename T>
  auto get_proxy_sync(const std::string &service_name, std::time_t timeout)
      -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = get_transport_sync(service_name, timeout);
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(service_name);
    }
    return prx;
  }
  /**
   * 获取服务代理，在实例建立过程中将阻塞执行执行 '协程'.
   * @param name 服务名
   * @param timeout 超时，毫秒
   * @return 代理std::shared_ptr<T>
   */
  template <typename T>
  auto get_proxy_co(const std::string &service_name, std::time_t timeout)
      -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = get_transport_co(service_name, timeout);
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(service_name);
    }
    return prx;
  }
  /**
   * 根据UUID获取代理，若缓存内未找到则立刻返回
   *
   * \return 代理
   */
  template <typename T> auto try_get_proxy() -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = try_get_transport(std::to_string(T::uuid()));
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(std::to_string(T::uuid()));
    }
    return prx;
  }
  /**
   * 根据UUID获取代理.
   *
   * \return 代理
   */
  template <typename T>
  auto get_proxy_sync(std::time_t timeout) -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = get_transport_sync(std::to_string(T::uuid()), timeout);
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(std::to_string(T::uuid()));
    }
    return prx;
  }
  /**
   * 根据UUID获取代理，在实例建立过程中将阻塞执行执行 '协程'..
   *
   * \param timeout 超时，毫秒
   * \return 代理
   */
  template <typename T>
  auto get_proxy_co(std::time_t timeout) -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    auto trans = get_transport_co(std::to_string(T::uuid()), timeout);
    if (!trans) {
      return nullptr;
    }
    auto prx = rpc::getService<T>(trans, true, get_rpc());
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(std::to_string(T::uuid()));
    }
    return prx;
  }
  /**
   * 获取服务代理,
   * 通常用于服务器反向调用客户端的服务，但是通过服务发现性能和必要性都有问题，所以
   * 通过这个方法可以高效的将内部服务与外部服务进行发送关联
   *
   * \param stub_call 外部通过proxy发送过来的调用
   * \return 代理std::shared_ptr<T>
   */
  template <typename T>
  auto get_proxy_from_peer(rpc::StubCallPtr stub_call) -> std::shared_ptr<T> {
    static_assert(has_uuid_method<T>::value, "Type need a uuid method");
    std::shared_ptr<T> prx;
    if (stub_call->getGlobalIndex() == rpc::INVALID_GLOBAL_INDEX) {
      prx = rpc::getService<T>(stub_call->getTransport(), true, get_rpc());
    } else {
      prx = rpc::getService<T>(stub_call->getGlobalIndex(),
                               stub_call->getTransport(), true, get_rpc());
    }
    if (prx) {
      prx->setRpc(get_rpc());
      prx->set_service_name(std::to_string(T::uuid()));
    }
    return prx;
  }
  /**
   * 随意输出的日志, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto verbose(const std::string &log) -> void = 0;
  /**
   * 信息日志, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto info(const std::string &log) -> void = 0;
  /**
   * 调试日志, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto diagnose(const std::string &log) -> void = 0;
  /**
   * 警告日志, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto warn(const std::string &log) -> void = 0;
  /**
   * 异常日志，捕获了异常, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto except(const std::string &log) -> void = 0;
  /**
   * 失败日志，错误可以恢复, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto fail(const std::string &log) -> void = 0;
  /**
   * 不可恢复日志，无法继续运行, [线程安全]
   *
   * \param log 日志内容
   */
  virtual auto fatal(const std::string &log) -> void = 0;
  /**
   * 获取定时调度器
   *
   * \return 定时调度器
   */
  virtual auto new_scheduler() -> SchedulePtr = 0;
  /**
   * 获取HTTP组件
   */
  virtual auto new_http() -> HttpPtr = 0;
  /**
   * 获取内存分配器.
   *
   * \return 内存分配器实例
   */
  virtual auto get_allocator() -> MemoryAllocator & = 0;
  /**
   * 获取命令注册组件
   */
  virtual auto new_command() -> CommandPtr = 0;
  /**
   * 获取Redis组件.
   *
   * \return
   */
  virtual auto new_redis() -> RedisPtr = 0;
  /**
   * 获取统计组件.
   *
   * \return
   */
  virtual auto get_statistics() -> ProcStat * = 0;
  /**
   * 获取模块日志.
   * \param name 模块名称
   * \return
   */
  virtual auto get_module_logger(const std::string &name) -> LoggerPtr = 0;
  /**
   * 获取本地时间.
   *
   * \return
   */
  virtual auto get_local_time() -> LocalTimePtr = 0;
  /**
   * 获取RPC调用统计组件.
   *
   * \return
   */
  virtual auto get_rpc_statistics() -> rpc::StubCallStatistics * = 0;
  /**
   * 获取CSV管理器.
   */
  virtual auto new_csv_manager() -> CsvManagerPtr = 0;
  /**
   * 获取容器控制台
   */
  virtual auto new_box_console(const std::string &name) -> BoxConsolePtr = 0;
  /**
   * 获取LuaService实例
   */
  virtual auto new_lua_service() -> LuaServicePtr = 0;
  /**
   * @brief 获取工具库接口
   * @return 工具库接口
   */
  virtual auto new_util() -> UtilPtr = 0;
  /**
   * 获取协程管理器
   *
   * \return 协程管理器接口
   */
  virtual auto new_co_manager() -> CoManagerPtr = 0;
  /**
   * @brief 获取自己主动连接到的容器代理的管道
   */
  virtual auto get_remote_proxy_transport()
      -> std::shared_ptr<rpc::Transport> = 0;
  /**
   * @brief 获取组件指针
   * @param comp_name 组件名
   * @param version 版本描述
   * @return 组件指针
   */
  virtual auto get_component(const std::string &comp_name,
                             const std::string &version = "")
      -> component::ComponentPtr = 0;

  /**
   * 获取服务容器的默认RPC.
   *
   * \return
   */
  virtual auto get_rpc() -> rpc::Rpc * = 0;

private:
  /**
   * 启动一个协程.
   *
   * \param co_func 协程函数
   * \return 协程ID
   */
  virtual auto schedule(CoFunction co_func) -> coroutine::CoroID = 0;
  /**
   * 关闭协程.
   *
   * \param co_id 协程ID
   * \return
   */
  virtual auto close(coroutine::CoroID co_id) -> void = 0;
  /**
   * 获取用于RPC通信的传输实例，如果没有则立即返回空实例.
   * @param name 服务名
   * @return 传输实例std::shared_ptr<rpc::Transport>
   */
  virtual auto try_get_transport(const std::string &name)
      -> std::shared_ptr<rpc::Transport> = 0;
  /**
   * 获取用于RPC通信的传输实例，在实例建立过程中将阻塞执行执行线程.
   * @param name 服务名
   * @param timeout 超时，毫秒
   * @return 传输实例std::shared_ptr<rpc::Transport>
   */
  virtual auto get_transport_sync(const std::string &name, std::time_t timeout)
      -> std::shared_ptr<rpc::Transport> = 0;
  /**
   * 获取用于RPC通信的传输实例，在实例建立过程中将阻塞执行执行'协程'.
   * @param name 服务名
   * @param timeout 超时，毫秒
   * @return 传输实例std::shared_ptr<rpc::Transport>
   */
  virtual auto get_transport_co(const std::string &service_name,
                                std::time_t timeout)
      -> std::shared_ptr<rpc::Transport> = 0;
  /**
   * 分配内存
   *
   * \param size 需要分配的长度
   * \return 内存地址
   */
  virtual auto allocate(std::size_t size) -> void * = 0;
  /**
   * 销毁内存
   *
   * \param p 内存地址
   */
  virtual auto deallocate(void *p) -> void = 0;
  /**
   * 获取协程运行器
   */
  virtual auto new_coro_runner() -> std::unique_ptr<CoroRunner> = 0;
  /**
   * 获取代理转发器.
   *
   * \return
   */
  virtual auto get_proxy_handler() -> rpc::ProxyHandler * = 0;
  /**
   * 异步获取服务管道
   *
   * @param service_name 服务名
   * @param cb 回调
   * \return CallbackAutoDeleterPtr
   */
  virtual auto get_transport(const std::string &service_name,
                             TransportCallback cb)
      -> CallbackAutoDeleterPtr = 0;
  /**
   * 添加服务管道回调
   *
   * @param service_name 服务名
   * @param cb 回调
   * \return 回调ID
   */
  virtual auto add_proxy_cb(const std::string &service_name,
                            TransportCallback cb) -> std::uint32_t = 0;
  /**
   * 删除服务管道回调
   *
   * @param cb_id 回调ID
   */
  virtual auto remove_proxy_cb(std::uint32_t cb_id) -> void = 0;
};

} // namespace service
} // namespace kratos

//
// 在implementation的头文件内使用, 用于声明一个服务代理
//
// 使用方法
//
// 在服务实现类内, 声明类型为TestProxy的代理智能指针:
//
// class MyServiceImpl : public MyService {
//   ...
//   DeclarePrx(TestProxy, my_prx);
//   ...
// };
//
#define DeclarePrx(T, name)                                                    \
  std::shared_ptr<T> name;                                                     \
  std::function<void(decltype(name), bool)> _##name##_query_cb_;               \
  kratos::service::CallbackAutoDeleterPtr _##name##_cb_deleter_;               \
  auto _##name##_cb_(kratos::service::TransEvent evt, std::uint32_t cb_id,     \
                     std::shared_ptr<rpc::Transport> trans_ptr)                \
      ->void {                                                                 \
    if (evt == kratos::service::TransEvent::CLOSE) {                           \
      if (_##name##_query_cb_) {                                               \
        try {                                                                  \
          _##name##_query_cb_(name, false);                                    \
        } catch (std::exception & e) {                                         \
          getContext()->write_log_line(                                        \
              klogger::Logger::EXCEPTION,                                      \
              "Proxy[" + std::string(#name) +                                  \
                  "] Query callback exception, resason[" + e.what() + "]");    \
        }                                                                      \
      }                                                                        \
      return;                                                                  \
    }                                                                          \
    if (!trans_ptr) {                                                          \
      return;                                                                  \
    }                                                                          \
    if (!getContext()) {                                                       \
      return;                                                                  \
    }                                                                          \
    if (!_##name##_cb_deleter_) {                                              \
      return;                                                                  \
    }                                                                          \
    if (_##name##_cb_deleter_->get_cb_id() != cb_id) {                         \
      return;                                                                  \
    }                                                                          \
    if (name->getID() != rpc::INVALID_PROXY_ID) {                              \
      name->setTransport(trans_ptr);                                           \
    } else {                                                                   \
      auto prx = rpc::getService<T>(trans_ptr, true, getContext()->get_rpc()); \
      if (prx) {                                                               \
        prx->setRpc(getContext()->get_rpc());                                  \
        prx->set_service_name(std::to_string(T::uuid()));                      \
        name->swap(prx);                                                       \
      }                                                                        \
    }                                                                          \
    if (name->isConnected()) {                                                 \
      if (_##name##_query_cb_) {                                               \
        try {                                                                  \
          _##name##_query_cb_(name, true);                                     \
        } catch (std::exception & e) {                                         \
          getContext()->write_log_line(                                        \
              klogger::Logger::EXCEPTION,                                      \
              "Proxy[" + std::string(#name) +                                  \
                  "] Query callback exception, resason[" + e.what() + "]");    \
        }                                                                      \
      }                                                                        \
    } else {                                                                   \
      getContext()->write_log_line(klogger::Logger::WARNING,                   \
                                   "Proxy UUID[" + std::to_string(T::uuid()) + \
                                       "] not found in RPC core");             \
    }                                                                          \
  }

//
// 在implementation的头文件内使用, 用于声明一个服务代理
//
// 使用方法
//
// 在服务实现类内, 声明类型为TestProxy的代理智能指针:
//
// class MyServiceImpl : public MyService {
//   ...
//   DeclarePrx(TestProxy, "service name", my_prx);
//   ...
// };
//
#define DeclareNamedPrx(T, cus_name, name)                                     \
  std::shared_ptr<T> name;                                                     \
  std::string _##name##_cus_name{cus_name};                                    \
  std::function<void(decltype(name), bool)> _##name##_query_cb_;               \
  kratos::service::CallbackAutoDeleterPtr _##name##_cb_deleter_;               \
  auto _##name##_cb_(kratos::service::TransEvent evt, std::uint32_t cb_id,     \
                     std::shared_ptr<rpc::Transport> trans_ptr)                \
      ->void {                                                                 \
    if (evt == kratos::service::TransEvent::CLOSE) {                           \
      if (_##name##_query_cb_) {                                               \
        try {                                                                  \
          _##name##_query_cb_(name, false);                                    \
        } catch (std::exception & e) {                                         \
          getContext()->write_log_line(                                        \
              klogger::Logger::EXCEPTION,                                      \
              "Proxy[" + std::string(#name) +                                  \
                  "] Query callback exception, resason[" + e.what() + "]");    \
        }                                                                      \
      }                                                                        \
      return;                                                                  \
    }                                                                          \
    if (!trans_ptr) {                                                          \
      return;                                                                  \
    }                                                                          \
    if (!getContext()) {                                                       \
      return;                                                                  \
    }                                                                          \
    if (!_##name##_cb_deleter_) {                                              \
      return;                                                                  \
    }                                                                          \
    if (_##name##_cb_deleter_->get_cb_id() != cb_id) {                         \
      return;                                                                  \
    }                                                                          \
    if (name->getID() != rpc::INVALID_PROXY_ID) {                              \
      name->setTransport(trans_ptr);                                           \
    } else {                                                                   \
      auto prx = rpc::getService<T>(trans_ptr, true, getContext()->get_rpc()); \
      if (prx) {                                                               \
        prx->setRpc(getContext()->get_rpc());                                  \
        prx->set_service_name(std::to_string(T::uuid()));                      \
        name->swap(prx);                                                       \
      }                                                                        \
    }                                                                          \
    if (name->isConnected()) {                                                 \
      if (_##name##_query_cb_) {                                               \
        try {                                                                  \
          _##name##_query_cb_(name, true);                                     \
        } catch (std::exception & e) {                                         \
          getContext()->write_log_line(                                        \
              klogger::Logger::EXCEPTION,                                      \
              "Proxy[" + std::string(#name) +                                  \
                  "] Query callback exception, resason[" + e.what() + "]");    \
        }                                                                      \
      }                                                                        \
    } else {                                                                   \
      getContext()->write_log_line(klogger::Logger::WARNING,                   \
                                   "Proxy UUID[" + std::to_string(T::uuid()) + \
                                       "] not found in RPC core");             \
    }                                                                          \
  }

//
// 在implementation实现类内使用, 用于获取一个服务代理
//
// 在服务实现类的,
// 类方法onAfterFork内使用QueryPrx在集群内获取类型为TestProxy类型的代理
//
// bool MyServiceImpl::onAfterFork(rpc::Rpc* rpc) {
//  ...
//  QueryPrx(TestProxy, MyServiceImpl, my_prx);
//  ...
// }
//
#define QueryPrx(T, Parent, name)                                              \
  if (getContext()) {                                                          \
    name = rpc::getService<T>(nullptr, true, getContext()->get_rpc());         \
    getContext()->get_proxy_helper<T>(                                         \
        _##name##_cb_deleter_,                                                 \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于检测服务代理的有效性,
// 如果失效则自动获取新的代理
//
#define CheckPrx(T, Parent, name)                                              \
  if (getContext() && name && (!name->isConnected())) {                        \
    getContext()->get_proxy_helper<T>(                                         \
        _##name##_cb_deleter_,                                                 \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于获取一个服务代理
//
// 在服务实现类的,
// 类方法onAfterFork内使用QueryPrx在集群内获取类型为TestProxy类型的代理
//
// bool MyServiceImpl::onAfterFork(rpc::Rpc* rpc) {
//  ...
//  QueryPrx(TestProxy, MyServiceImpl, my_prx);
//  ...
// }
//
#define QueryNamedPrx(T, Parent, name)                                         \
  if (getContext()) {                                                          \
    name = rpc::getService<T>(nullptr, true, getContext()->get_rpc());         \
    getContext()->get_named_proxy_helper<T>(                                   \
        _##name##_cus_name, _##name##_cb_deleter_,                             \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于检测服务代理的有效性,
// 如果失效则自动获取新的代理
//
#define CheckNamedPrx(T, Parent, name)                                         \
  if (getContext() && name && (!name->isConnected())) {                        \
    getContext()->get_named_proxy_helper<T>(                                   \
        _##name##_cus_name, _##name##_cb_deleter_,                             \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于获取一个服务代理
//
// 在服务实现类的,
// 类方法onAfterFork内使用QueryPrx在集群内获取类型为TestProxy类型的代理
//
// bool MyServiceImpl::onAfterFork(rpc::Rpc* rpc) {
//  ...
//  QueryPrxCB(TestProxy, MyServiceImpl, my_prx, cb);
//  ...
// }
//
#define QueryPrxCB(T, Parent, name, cb)                                        \
  _##name##_query_cb_ = cb;                                                    \
  if (getContext()) {                                                          \
    name = rpc::getService<T>(nullptr, true, getContext()->get_rpc());         \
    getContext()->get_proxy_helper<T>(                                         \
        _##name##_cb_deleter_,                                                 \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于检测服务代理的有效性,
// 如果失效则自动获取新的代理
//
#define CheckPrxCB(T, Parent, name, cb)                                        \
  if (getContext() && name && (!name->isConnected())) {                        \
    _##name##_query_cb_ = cb;                                                  \
    getContext()->get_proxy_helper<T>(                                         \
        _##name##_cb_deleter_,                                                 \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于获取一个服务代理
//
// 在服务实现类的,
// 类方法onAfterFork内使用QueryPrx在集群内获取类型为TestProxy类型的代理
//
// bool MyServiceImpl::onAfterFork(rpc::Rpc* rpc) {
//  ...
//  QueryPrxCB(TestProxy, MyServiceImpl, my_prx, cb);
//  ...
// }
//
#define QueryNamedPrxCB(T, Parent, name, cb)                                   \
  _##name##_query_cb_ = cb;                                                    \
  if (getContext()) {                                                          \
    name = rpc::getService<T>(nullptr, true, getContext()->get_rpc());         \
    getContext()->get_named_proxy_helper<T>(                                   \
        _##name##_cus_name, _##name##_cb_deleter_,                             \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }

//
// 在implementation实现类内使用, 用于检测服务代理的有效性,
// 如果失效则自动获取新的代理
//
#define CheckNamedPrxCB(T, Parent, name, cb)                                   \
  if (getContext() && name && (!name->isConnected())) {                        \
    _##name##_query_cb_ = cb;                                                  \
    getContext()->get_named_proxy_helper<T>(                                   \
        _##name##_cus_name, _##name##_cb_deleter_,                             \
        std::bind(&Parent::_##name##_cb_, this, std::placeholders::_1,         \
                  std::placeholders::_2, std::placeholders::_3));              \
  }
